# -*- coding: utf-8 -*-
import os
import gtk
import gobject
import zipfile
import traceback 

import fb2

from pybs import settings
from pybs import core
from pybs import strunicode as su

from . import fb2doc
from pybs.strunicode import normalize

def edit_book_dialog(book_path, parent_window):
    """
    Display fb2 book editing dialog
    
    @param book_path: path to book file
    @param parent_window: gtk.Window instance that should own book edit dialog
    @return: True if book file was modified, False otherwise
    """
    base_dir = os.path.dirname(os.path.realpath(__file__))
    xml = gtk.glade.XML(os.path.join(base_dir, "fb2.glade"), root="edit_book_info_dialog",
        domain="pybookshelf")
    
    dialog = xml.get_widget("edit_book_info_dialog")
    author_details_vbox = xml.get_widget("author_details_vbox")
    treeview = xml.get_widget("authors_treeview")
    title_entry = xml.get_widget("title_entry")
    
    book = fb2doc.parse_file(book_path)
    
    # display-name, first-name, midle-name, last-name, nickname, email, homepage
    treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, \
                              gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
    treeview.set_model(treestore)
    tvcolumn = gtk.TreeViewColumn("fff")
    tvcell = gtk.CellRendererText()
    tvcolumn.pack_start(tvcell)
    tvcolumn.add_attribute(tvcell, "text", 0)
    treeview.append_column(tvcolumn)
    

    # setup presets menu
    presets_menu = gtk.Menu()
    xml.get_widget("presets_button").set_data("menu", presets_menu)
    mi = gtk.MenuItem(_("Remember selected"))
    mi.connect("activate", on_preset_add_selected_author, treeview, presets_menu)
    presets_menu.append(mi)
    mi = gtk.SeparatorMenuItem()
    presets_menu.append(mi)
    # fill with remembered items
    mi = gtk.MenuItem(_("(empty)"))
    mi.set_sensitive(False)
    presets_menu.append(mi)
    mi = gtk.SeparatorMenuItem()
    presets_menu.append(mi)
    mi = gtk.MenuItem(_(u"Edit presets…"))
    mi.connect("activate", on_preset_edit, dialog, treeview, presets_menu)
    presets_menu.append(mi)
    presets_menu.show_all()
    
    reload_presets_menu(presets_menu, treeview)
    
    author_components = ["firstname", "middlename", "lastname", "nickname",
                         "email", "homepage"]
    for a in book.authors():
        author_details = [getattr(a, x) for x in author_components] 
        
        treestore.append(None, [author_display_name(*author_details)]+author_details )
        
    def on_cursor_changed(treeview):
        """
        Set author components text entries values against current list element
        """
        path, col = treeview.get_cursor()
        if path is None:
            author_details_vbox.hide()
            return
        model = treeview.get_model()
        iter = model.get_iter(path)
        details = dict()
        
        for c in author_components:
            #details[c] = model.get_value(iter, i)
            value = model.get_value(iter, author_components.index(c)+1)
            if value is None:
                value = ""
            xml.get_widget(c+"_entry").set_text(value)
        
        author_details_vbox.show()

    def on_entry_changed(entry, component_name, pos):
        path, col = treeview.get_cursor()
        model = treeview.get_model()
        iter = model.get_iter(path)
        model.set_value(iter, pos, entry.get_text())
        # update author display name
        components = model.get(iter, 1,2,3,4,5,6)
        model.set_value(iter, 0, author_display_name(*components))
        
    settings.restore_window_geometry(dialog, "edit_book", plugin="fb2")
    handler_pos = settings.get_int("ui/edit_book_handle_pos", plugin="fb2")
    xml.get_widget("hpaned1").set_position(handler_pos)
    title_entry.set_text(book.title())
    
    dialog.connect("configure_event", on_resize, "edit_book")
    treeview.connect("cursor-changed", on_cursor_changed)
    xml.get_widget("hpaned1").connect("notify", on_divider_move)
    xml.get_widget("add_author_button").connect("clicked", on_add_author, treeview)
    xml.get_widget("remove_author_button").connect("clicked", on_remove_author, treeview)
    xml.get_widget("presets_button").connect("pressed", on_presets_menu, dialog, treeview)
    
    for c in author_components:
        xml.get_widget(c+"_entry").connect("changed", on_entry_changed, c, author_components.index(c)+1)
    
    author_details_vbox.hide()
    
    dialog.set_transient_for(parent_window)
    
    while True:
        response = dialog.run()
        if response == 1:
            # update object book and save updated content
            if title_entry.get_text() == "":
                core.error(_("Book title may not be empty"), parent_window=dialog)
                continue
            
            if treestore.get_iter_root() is None:
                core.error(_("Authors list may not be empty"), parent_window=dialog)
                continue
                
            book.set_title(su.ustr2unicode(title_entry.get_text()))
            authors_list = []
            
            def authors_iter_func(model, path, i):
                it = iter(author_components)
                a = fb2doc.Author20()
                for value in model.get(i, 1,2,3,4,5,6):
                    name = it.next()
                    if value == "" or value is None:
                        value = None
                    else:
                        value = su.ustr2unicode(value)
                        
                    setattr(a, name, value)
                    
                authors_list.append(a)
                    
            treestore.foreach(authors_iter_func)
            try:
                book.set_authors(authors_list)
            except fb2.FormatError:
                core.error(_("Invalid data"), parent_window=dialog)
                continue
        break
        
    dialog.hide_all()
    
    if response == 1:
        
        try:
            # try to save file into temporary location
            book_xml = str(book)
            tmp_file_name = book_path + ".tmp"
            if book_path.lower().endswith("fb2.zip"):
                # save zip
                zip_filename = normalize.translit(normalize.normalize(book.title()))+".fb2"
                zip = zipfile.ZipFile(tmp_file_name, "w", zipfile.ZIP_DEFLATED, allowZip64=False)
                zip.writestr(zip_filename.encode("ISO-8859-1"), str(book))
                zip.close()
            else:
                # save fb2
                f = open(tmp_file_name, "w")
                f.write(str(book))
                f.close()
                
            # rename temporary file into real one
            os.rename(tmp_file_name, book_path)
        except Exception, e:
            message = _("Unhandled exception:\n")
            message += traceback.format_exc()
            core.error(message)
        
    dialog.destroy()
    
    return response == 1

def run_authors_presets_dialog(parent_window):
    base_dir = os.path.dirname(os.path.realpath(__file__))
    xml = gtk.glade.XML(os.path.join(base_dir, "fb2.glade"), root="edit_authors_presets_dialog",
        domain="pybookshelf")
    
    dialog = xml.get_widget("edit_authors_presets_dialog")
    treeview = xml.get_widget("items_treeview")
    treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

    treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, \
                              gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
    treeview.set_model(treestore)
    tvcolumn = gtk.TreeViewColumn("fff")
    tvcell = gtk.CellRendererText()
    tvcolumn.pack_start(tvcell)
    tvcolumn.add_attribute(tvcell, "text", 0)
    treeview.append_column(tvcolumn)
    
    items = settings.get_list("authors_presets", plugin="fb2")
    for components in items:
        treestore.append(None, [author_display_name(*components),]+components)
    
    settings.restore_window_geometry(dialog, "edit_authors_presets", plugin="fb2")
    dialog.connect("configure_event", on_resize, "edit_authors_presets")
    dialog.set_transient_for(parent_window)
    response = dialog.run()
    
    if response == 1:
        # delete selected items
        (model, paths) = treeview.get_selection().get_selected_rows()
        [model.remove(iter) for iter in [model.get_iter(path) for path in paths]]
            
        items = []
        def items_iter_func(model, path, iter):
            items.append([x for x in model.get(iter, 1,2,3,4,5,6)])

        treestore.foreach(items_iter_func)
        settings.set_list("authors_presets", items, plugin="fb2")
        
    dialog.destroy()
    
def author_display_name(firstname, middlename, lastname, nickname, email, homepage):
    name = core.smart_join(firstname, middlename, lastname)
    if name == "":
        name = nickname
        
    return name


def on_resize(dialog, event, settings_prefix):
    settings.remember_window_geometry(dialog, settings_prefix, plugin="fb2")
    
def on_divider_move(paned, gparamspec):
    if gparamspec.name == "position":
        pos = paned.get_position()
        settings.set_int("ui/edit_book_handle_pos", pos, plugin="fb2")

def on_add_author(button, treeview):
    model = treeview.get_model()
    model.append(None, ["first-name", "first-name"] + ["" for x in xrange(5)])

def on_remove_author(button, treeview):
    path, col = treeview.get_cursor()
    if path is None:
        return
    
    model = treeview.get_model()
    iter = model.remove(model.get_iter(path))
    
def on_presets_menu(button, dialog, treeview):
    r = button.get_allocation()
    x, y = button.translate_coordinates(dialog, 0, r.height)
    wx, wy = dialog.window.get_origin()
    menu = button.get_data("menu")
    
    menu.popup(None, None, 
        lambda menu: (x+wx, y+wy, True),
        0,
        gtk.get_current_event_time())

def reload_presets_menu(presets_menu, treeview):
    
    # first delete all existing menuitems (all except first two and last two)
    children = presets_menu.get_children()
    l = len(children)
    for x in [n+2 for n in xrange(l-4)]:
        presets_menu.remove(children[x])

    items = settings.get_list("authors_presets", plugin="fb2")
    if len(items) == 0:
        mi = gtk.MenuItem(_("(empty)"))
        mi.set_sensitive(False)
        presets_menu.insert(mi, 2)
    else:
        next = 2
        for row in items:
            mi = gtk.MenuItem(author_display_name(*row))
            mi.set_data("components", row)
            mi.connect("activate", on_preset_activate, treeview)
            presets_menu.insert(mi, next)
            next += 1
        
    presets_menu.show_all()

def on_preset_add_selected_author(menuitem, treeview, menu):
    path, col = treeview.get_cursor()
    if path is None:
        return
    
    model = treeview.get_model()
    components = [x for x in model.get(model.get_iter(path), 1,2,3,4,5,6)]
    items = settings.get_list("authors_presets", plugin="fb2")
    items.insert(0, components)
    settings.set_list("authors_presets", items, plugin="fb2")
    reload_presets_menu(menu, treeview)

def on_preset_edit(menuitem, dialog, treeview, menu):
    run_authors_presets_dialog(dialog)
    reload_presets_menu(menu, treeview)    
    
def on_preset_activate(menuitem, treeview):
    path, col = treeview.get_cursor()
    if path is None:
        return
    
    model = treeview.get_model()
    iter = model.get_iter(path)
    components = menuitem.get_data("components")
    model.set_value(iter, 0, author_display_name(*components))
    i = 1
    for c in components:
        model.set_value(iter, i, c)
        i += 1
    treeview.set_cursor(path)
